﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;

namespace Vbyte.SharpOrm.SqlDb
{
    /// <summary>
    /// 基本通用的过滤器、SQL数据筛选设置基类
    /// </summary>
    public class SqlNativeConstrains : ISqlConstrains
    {
        /// <summary>
        /// 新建一个原生SQL约束实例
        /// </summary>
        public SqlNativeConstrains()
            : base()
        { }

        /// <summary>
        /// where条件限制集合
        /// </summary>
        protected List<string> ConditionList = new List<string>();

        /// <summary>
        /// 自定义列集合
        /// </summary>
        protected List<string> CustomFiledList = new List<string>();

        /// <summary>
        /// 自定义值集合
        /// </summary>
        protected List<string> CustomValueList = new List<string>();

        /// <summary>
        /// Group by 字段集合
        /// </summary>
        protected List<string> GroupByFieldList = new List<string>();

        #region ISqlConstrains 成员

        /// <summary>
        /// where条件限制集合
        /// </summary>
        /// <returns></returns>
        public string[] GetConditions()
        {
            return ConditionList.ToArray();
        }


        /// <summary>
        /// 获取自定义列集合
        /// </summary>
        /// <returns></returns>
        public List<string> GetCustomFieldList()
        {
            return CustomFiledList;
        }

        /// <summary>
        /// 获取自定义值集合
        /// </summary>
        /// <returns></returns>
        public List<string> GetCustomValueList()
        {
            return CustomValueList;
        }

        /// <summary>
        /// 安全添加到集合列表
        /// </summary>
        /// <param name="tVal">添加的字符值</param>
        /// <param name="emptyIgnore">如果集合为空则忽略添加的前置字符，否则添加该前置字符。</param>
        /// <param name="sourceList">原始集合列表引用</param>
        protected void SqlSafeAdd(string tVal, string emptyIgnore, ref List<string> sourceList)
        {
            if (sourceList.Count == 0)
            {
                sourceList.Add(tVal);
            }
            else
            {
                sourceList.Add(String.Concat(" ", emptyIgnore, " ", tVal));
            }
        }

        /// <summary>
        /// 添加AND关系的条件限制(原生SQL)
        /// </summary>
        /// <param name="sqlCondition">条件限制语句</param>
        /// <returns>应用了限制之后的过滤筛选器</returns>
        public ISqlConstrains NativeCondition(string sqlCondition)
        {
            SqlSafeAdd(sqlCondition, "AND", ref ConditionList);
            return this;
        }

        /// <summary>
        /// 添加OR关系的条件限制(原生SQL)
        /// </summary>
        /// <param name="sqlCondition">条件限制语句</param>
        /// <returns>应用了限制之后的过滤筛选器</returns>
        public ISqlConstrains OrNativeCondition(string sqlCondition)
        {
            SqlSafeAdd(sqlCondition, "OR", ref ConditionList);
            return this;
        }

        /// <summary>
        /// 添加AND ()关系的条件限制(原生SQL)
        /// </summary>
        /// <param name="sqlCondition">条件限制语句</param>
        /// <returns>应用了限制之后的过滤筛选器</returns>
        public ISqlConstrains WrapCondition(string sqlCondition)
        {
            return NativeCondition(String.Concat("( ", sqlCondition, " )"));
        }

        /// <summary>
        /// 添加OR ()关系的条件限制(原生SQL)
        /// </summary>
        /// <param name="sqlCondition">条件限制语句</param>
        /// <returns>应用了限制之后的过滤筛选器</returns>
        public ISqlConstrains OrWrapCondition(string sqlCondition)
        {
            return OrNativeCondition(String.Concat("( ", sqlCondition, " )"));
        }

        /// <summary>
        /// Group By 字段集合
        /// </summary>
        /// <returns></returns>
        public string[] GetGroupByConfig()
        {
            return GroupByFieldList.ToArray();
        }

        /// <summary>
        /// 获取自定义的Group By 原生字段分组排序
        /// </summary>
        /// <param name="sqlGroupByFields">Group By 原生字段</param>
        /// <returns>应用了Group By 之后的过滤筛选器</returns>
        public ISqlConstrains GroupByFields(string sqlGroupByFields)
        {
            SqlSafeAdd(sqlGroupByFields, ",", ref GroupByFieldList);
            return this;
        }

        /// <summary>
        /// 限制某属性（字段）必须在集合中
        /// </summary>
        /// <typeparam name="T">集合类型</typeparam>
        /// <param name="propName">属性(字段)名称</param>
        /// <param name="array">值集合</param>
        /// <returns>应用了在集合中规则的过滤筛选器</returns>
        public ISqlConstrains In<T>(string propName, T[] array)
            where T : IConvertible
        {
            if (typeof(T) == typeof(string))
            {
                return In(propName, "'" + string.Join("','",
                    Array.ConvertAll<T, string>(array, (T obj) => Convert.ToString(obj))
                 ) + "'"
                );
            }
            else
            {
                return In(propName, string.Join(",",
                    Array.ConvertAll<T, string>(array, (T obj) => Convert.ToString(obj))
                    )
                );
            }
        }

        /// <summary>
        /// 限制某属性（字段）必须不在集合中
        /// </summary>
        /// <typeparam name="T">集合类型</typeparam>
        /// <param name="propName">属性(字段)名称</param>
        /// <param name="array">值集合</param>
        /// <returns>应用了不在集合中规则的过滤筛选器</returns>
        public ISqlConstrains NotIn<T>(string propName, T[] array)
            where T : IConvertible
        {
            if (typeof(T) == typeof(string))
            {
                return NotIn(propName, "'" + string.Join("','",
                    Array.ConvertAll<T, string>(array, (T obj) => Convert.ToString(obj))
                 ) + "'"
                );
            }
            else
            {
                return NotIn(propName, string.Join(",",
                    Array.ConvertAll<T, string>(array, (T obj) => Convert.ToString(obj))
                    )
                );
            }
        }

        /// <summary>
        /// 限制某属性（字段）必须在查询集合中
        /// </summary>
        /// <param name="propName">属性(字段)名称</param>
        /// <param name="nativeSqlCollection">查询集合</param>
        /// <returns>应用了在集合中规则的过滤筛选器</returns>
        public ISqlConstrains In(string propName, string nativeSqlCollection)
        {
            SqlSafeAdd(String.Concat(propName, " in ", "( ", nativeSqlCollection, " )"), "AND", ref ConditionList);
            return this;
        }

        /// <summary>
        /// 限制某属性（字段）必须不在查询集合中
        /// </summary>
        /// <param name="propName">属性(字段)名称</param>
        /// <param name="nativeSqlCollection">查询集合</param>
        /// <returns>应用了不在集合中规则的过滤筛选器</returns>
        public ISqlConstrains NotIn(string propName, string nativeSqlCollection)
        {
            SqlSafeAdd(String.Concat(propName, " not in ", "( ", nativeSqlCollection, " )"), "AND", ref ConditionList);
            return this;
        }

        /// <summary>
        /// 添加自定义字段的名称(语句定义）和相匹配的值
        /// </summary>
        /// <param name="fieldName">字段名称</param>
        /// <param name="fieldValue">字段值</param>
        /// <returns>应用了定义字段规则的过滤筛选器</returns>
        public ISqlConstrains WithCustomField(string fieldName, string fieldValue)
        {
            CustomFiledList.Add(fieldName);
            CustomValueList.Add(fieldValue);
            return this;
        }

        #endregion

        private static Dictionary<string, MethodInfo> JsInvokableDict = new Dictionary<string, MethodInfo>(StringComparer.InvariantCultureIgnoreCase);

        /// <summary>
        /// 获取客户端可直接调用的约束函数词典
        /// </summary>
        public static Dictionary<string, MethodInfo> GetJsInvokeDict()
        {
            if (JsInvokableDict.Count == 0)
            {
                Type instanceType = typeof(SqlNativeConstrains);
                //构建可调用词典
                foreach (MethodInfo mi in instanceType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (mi.IsGenericMethod) continue;
                    JsInvokableDict.Add(mi.Name, mi);
                }
            }
            return JsInvokableDict;
        }

        /// <summary>
        /// 从客户端javascript脚本加载约束配置
        /// <para>备注：一个函数独占一行，各个参数间必须用用“ , ”隔开。</para>
        /// </summary>
        /// <param name="javascript">客户端的原始Javascript脚本</param>
        /// <returns>返回从JS调用生成的约束对象</returns>
        public static SqlNativeConstrains LoadFromJsInvoke(string javascript)
        {
            SqlNativeConstrains constrains = new SqlNativeConstrains();
            //([a-zA-z]+)\((.+)\)
            string fnPattern = "([a-zA-z]+)\\((.+)\\)";
            MatchCollection mc = Regex.Matches(javascript, fnPattern);
            Type instanceType = typeof(SqlNativeConstrains);

            //构建可调用词典
            Dictionary<string, MethodInfo> jsInvokeDict = GetJsInvokeDict();
            MethodInfo method = null;
            object[] invokParams = new object[0];
            string[] jsParams = null;
            foreach (Match m in mc)
            {
                if (jsInvokeDict.ContainsKey(m.Groups[1].Value))
                {
                    method = jsInvokeDict[m.Groups[1].Value];
                    jsParams = Regex.Split(m.Groups[2].Value, "\\s,\\s");
                    invokParams = new object[jsParams.Length];
                    for (int i = 0; i < jsParams.Length; i++)
                    {
                        invokParams[i] = jsParams[i].Trim('\'', '"');
                    }
                    try
                    {
                        constrains = (SqlNativeConstrains)method.Invoke(constrains, invokParams);
                    }
                    catch (Exception)
                    {
                        //Console.WriteLine("Len:{0}", jsParams.Length);
                        //Console.WriteLine("Error In: {0}({1})", m.Groups[1].Value, m.Groups[2].Value);
                    }
                }
            }
            return constrains;
        }

    }
}
